home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / wrlib / draw.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-14  |  14.8 KB  |  606 lines

  1. /* draw.c - pixel plotting, line drawing
  2.  * 
  3.  *  Raster graphics library
  4.  * 
  5.  *  Copyright (c) 1998 Dan Pascu
  6.  *  Copyright (c) 2000 Alfredo K. Kojima
  7.  *
  8.  *  This library is free software; you can redistribute it and/or
  9.  *  modify it under the terms of the GNU Library General Public
  10.  *  License as published by the Free Software Foundation; either
  11.  *  version 2 of the License, or (at your option) any later version.
  12.  *  
  13.  *  This library is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  *  Library General Public License for more details.
  17.  *  
  18.  *  You should have received a copy of the GNU Library General Public
  19.  *  License along with this library; if not, write to the Free
  20.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23. #include <config.h>
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <assert.h>
  28.  
  29. #include "wraster.h"
  30.  
  31.  
  32. #define MIN(a,b)    ((a) < (b) ? (a) : (b))
  33. #define MAX(a,b)    ((a) > (b) ? (a) : (b))
  34.  
  35.  
  36.  
  37. /*
  38.  * Returns the color of the pixel at coordinates (x, y) in "color".
  39.  */
  40. Bool
  41. RGetPixel(RImage *image, int x, int y, RColor *color)
  42. {
  43.     int ofs;
  44.  
  45.     assert(image!=NULL);
  46.     if (x < 0 || x >= image->width
  47.     || y < 0 || y >= image->height)
  48.     return False;
  49.  
  50.     if (image->format == RRGBAFormat) {
  51.     ofs = (y*image->width + x) * 4;
  52.     color->red = image->data[ofs];
  53.     color->green = image->data[ofs++];
  54.     color->blue = image->data[ofs++];
  55.     color->alpha = image->data[ofs];
  56.     } else {
  57.     ofs = (y*image->width + x) * 3;
  58.     color->red = image->data[ofs++];
  59.     color->green = image->data[ofs++];
  60.     color->blue = image->data[ofs++];
  61.     /* If the image does not have alpha channel, we consider alpha 255 */
  62.     color->alpha = 255;
  63.     }
  64.  
  65.     return True;
  66. }
  67.  
  68.  
  69. void
  70. RPutPixel(RImage *image, int x, int y, RColor *color)
  71. {
  72.     unsigned char *ptr;
  73.  
  74.     assert(image!=NULL);
  75.     assert(color!=NULL);
  76.     if (x < 0 || x >= image->width || y < 0 || y >= image->height)
  77.     return;
  78.  
  79.     if (image->format == RRGBAFormat) {
  80.     ptr = image->data + (y*image->width + x) * 4;
  81.     } else {
  82.     ptr = image->data + (y*image->width + x) * 3;
  83.     }
  84.  
  85.     if (color->alpha==255) {
  86.     *ptr++ = color->red;
  87.         *ptr++ = color->green;
  88.         *ptr++ = color->blue;
  89.     if (image->format == RRGBAFormat) {
  90.         *ptr = 255;
  91.     }
  92.     } else {
  93.         register int alpha, nalpha, r, g, b;
  94.  
  95.         r = color->red;
  96.         g = color->green;
  97.         b = color->blue;
  98.         alpha = color->alpha;
  99.         nalpha = 255 - alpha;
  100.  
  101.         *ptr++ = (((int)*ptr * nalpha) + (r * alpha))/256;
  102.         *ptr++ = (((int)*ptr * nalpha) + (g * alpha))/256;
  103.         *ptr++ = (((int)*ptr * nalpha) + (b * alpha))/256;
  104.         if (image->format == RRGBAFormat) {
  105.             *ptr = alpha + ((int)*ptr * nalpha)/256;
  106.     }
  107.     }
  108. }
  109.  
  110.  
  111. static void
  112. operatePixel(RImage *image, int ofs, int operation, RColor *color)
  113. {
  114.     unsigned char *sr, *sg, *sb, *sa;
  115.     register int alpha, nalpha, tmp;
  116.     int hasAlpha = image->format == RRGBAFormat;
  117.  
  118.     alpha = color->alpha;
  119.     nalpha = 255 - alpha;
  120.  
  121.     sr = image->data + ofs*(hasAlpha ? 4 : 3);
  122.     sg = image->data + ofs*(hasAlpha ? 4 : 3) + 1;
  123.     sb = image->data + ofs*(hasAlpha ? 4 : 3) + 2;
  124.     sa = image->data + ofs*(hasAlpha ? 4 : 3) + 3;
  125.     
  126.     switch (operation) {
  127.      case RClearOperation:
  128.     *sr = 0;
  129.     *sg = 0;
  130.     *sb = 0;
  131.     if (hasAlpha)
  132.         *sa = 0;
  133.     break;
  134.      case RCopyOperation:
  135.     *sr = color->red;
  136.     *sg = color->green;
  137.     *sb = color->blue;
  138.     if (hasAlpha)
  139.         *sa = color->alpha;
  140.     break;
  141.      case RNormalOperation:
  142.     if (color->alpha==255) {
  143.         *sr = color->red;
  144.         *sg = color->green;
  145.         *sb = color->blue;
  146.         if (hasAlpha)
  147.         *sa = 255;
  148.     } else {
  149.         *sr = (((int)*sr * nalpha) + ((int)color->red * alpha))/256;
  150.         *sg = (((int)*sg * nalpha) + ((int)color->green * alpha))/256;
  151.         *sb = (((int)*sb * nalpha) + ((int)color->blue * alpha))/256;
  152.     }
  153.     break;
  154.      case RAddOperation:
  155.     tmp = color->red + *sr;
  156.     *sr = MIN(255, tmp);
  157.     tmp = color->green + *sg;
  158.     *sg = MIN(255, tmp);
  159.     tmp = color->blue + *sb;
  160.     *sb = MIN(255, tmp);
  161.     if (hasAlpha)
  162.         *sa = MIN(*sa, color->alpha);
  163.     break;
  164.      case RSubtractOperation:
  165.     tmp = *sr - color->red;
  166.     *sr = MAX(0, tmp);
  167.     tmp = *sg - color->green;
  168.     *sg = MAX(0, tmp);
  169.     tmp = *sb - color->blue;
  170.     *sb = MAX(0, tmp);
  171.     if (hasAlpha)
  172.         *sa = MIN(*sa, color->alpha);
  173.     break;
  174.     }
  175. }
  176.  
  177.  
  178.  
  179. void
  180. ROperatePixel(RImage *image, int operation, int x, int y, RColor *color)
  181. {
  182.     int ofs;
  183.  
  184.     assert(image!=NULL);
  185.     assert(color!=NULL);
  186.     assert(x >= 0 && x < image->width);
  187.     assert(y >= 0 && y < image->height);
  188.  
  189.     ofs = y*image->width + x;
  190.     
  191.     operatePixel(image, ofs, operation, color);
  192. }
  193.  
  194.  
  195. void
  196. RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
  197. {
  198.     register int x, y, i;
  199.  
  200.     assert(image!=NULL);
  201.     assert(points!=NULL);
  202.  
  203.     x = y = 0;
  204.  
  205.     for (i=0; i<npoints; i++) {
  206.         if (mode == RAbsoluteCoordinates) {
  207.             x = points[i].x;
  208.             y = points[i].y;
  209.         } else {
  210.             x += points[i].x;
  211.             y += points[i].y;
  212.         }
  213.         RPutPixel(image, x, y, color);
  214.     }
  215. }
  216.  
  217.  
  218. void
  219. ROperatePixels(RImage *image, int operation, RPoint *points, int npoints, 
  220.            int mode, RColor *color)
  221. {
  222.     register int x, y, i;
  223.  
  224.     assert(image!=NULL);
  225.     assert(points!=NULL);
  226.  
  227.     x = y = 0;
  228.  
  229.     for (i=0; i<npoints; i++) {
  230.         if (mode == RAbsoluteCoordinates) {
  231.             x = points[i].x;
  232.             y = points[i].y;
  233.         } else {
  234.             x += points[i].x;
  235.             y += points[i].y;
  236.         }
  237.         ROperatePixel(image, operation, x, y, color);
  238.     }
  239. }
  240.  
  241.  
  242. static Bool
  243. clipLineInRectangle(int xmin, int ymin, int xmax, int ymax,
  244.             int *x1, int *y1, int *x2, int *y2)
  245. {
  246. #define TOP    (1<<0)
  247. #define BOT    (1<<1)
  248. #define LEF    (1<<2)
  249. #define RIG    (1<<3)
  250. #define CHECK_OUT(X,Y)    (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
  251.              | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
  252.  
  253.     int ocode1, ocode2, ocode;
  254.     int accept = 0;
  255.     int x, y;
  256.  
  257.     ocode1 = CHECK_OUT(*x1, *y1);
  258.     ocode2 = CHECK_OUT(*x2, *y2);
  259.  
  260.     for(;;) {
  261.     if (!ocode1 && !ocode2) { /* completely inside */
  262.         accept = 1;
  263.         break;
  264.     } else if (ocode1 & ocode2) {
  265.         break;
  266.     }
  267.  
  268.     if (ocode1)
  269.         ocode = ocode1;
  270.     else
  271.         ocode = ocode2;
  272.  
  273.     if (ocode & TOP) {
  274.         x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
  275.         y = ymax;
  276.     } else if (ocode & BOT) {
  277.         x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
  278.         y = ymin;
  279.     } else if (ocode & RIG) {
  280.         y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
  281.         x = xmax;
  282.     } else if (ocode & LEF) {
  283.         y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
  284.         x = xmin;
  285.     }
  286.  
  287.     if (ocode == ocode1) {
  288.         *x1 = x;
  289.         *y1 = y;
  290.         ocode1 = CHECK_OUT(x, y);
  291.     } else {
  292.         *x2 = x;
  293.         *y2 = y;
  294.         ocode2 = CHECK_OUT(x, y);
  295.     }
  296.     }
  297.     
  298.     return accept;
  299. }
  300.  
  301.  
  302. /*
  303.  * This routine is a generic drawing routine, based on Bresenham's line
  304.  * drawing algorithm.
  305.  */
  306. static int
  307. genericLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color,
  308.             int operation, int polyline)
  309. {
  310.     int i, err, du, dv, du2, dv2, uofs, vofs, last;
  311.  
  312.     assert(image!=NULL);
  313.  
  314.     if (!clipLineInRectangle(0, 0, image->width-1, image->height-1,
  315.                  &x0, &y0, &x1, &y1))
  316.     return True;
  317.  
  318.     if (x0 < x1) {
  319.         du = x1 - x0;
  320.         uofs = 1;
  321.     } else {
  322.         du = x0 - x1;
  323.         uofs = -1;
  324.     }
  325.     if (y0 < y1) {
  326.         dv = y1 -y0;
  327.         vofs = image->width;
  328.     } else {
  329.         dv = y0 - y1;
  330.         vofs = -image->width;
  331.     }
  332.  
  333.     if (du < dv) {
  334.         /* Swap coordinates between them, so that always du>dv */
  335.         i = du; du = dv; dv = i;
  336.         i = uofs; uofs = vofs; vofs = i;
  337.     }
  338.  
  339.     err = 0;
  340.     du2 = du<<1;
  341.     dv2 = dv<<1;
  342.     last = (polyline) ? du-1 : du;
  343.  
  344.     if (color->alpha==255 || operation==RCopyOperation) {
  345.     unsigned char *ptr;
  346.  
  347.     if (image->format == RRGBAFormat)
  348.         i = (y0*image->width + x0) * 4;
  349.     else
  350.         i = (y0*image->width + x0) * 3;
  351.     ptr = image->data + i;
  352.  
  353.     for (i=0; i<=last; i++) {
  354.         /* Draw the pixel */
  355.         *ptr = color->red;
  356.         *(ptr+1) = color->green;
  357.         *(ptr+2) = color->blue;
  358.         if (image->format == RRGBAFormat)
  359.         *(ptr+3) = 255;
  360.  
  361.         /* Compute error for NeXT Step */
  362.         err += dv2;
  363.         if (err >= du) {
  364.         if (image->format == RRGBAFormat)
  365.             ptr += vofs*4;
  366.         else
  367.             ptr += vofs*3;
  368.         err -= du2;
  369.         }
  370.         if (image->format == RRGBAFormat)
  371.         ptr += uofs*4;
  372.         else
  373.         ptr += uofs*3;
  374.     }
  375.     } else {
  376.     register int ofs = y0*image->width + x0;
  377.     
  378.     for (i=0; i<=last; i++) {
  379.         /* Draw the pixel */
  380.         operatePixel(image, ofs, operation, color);
  381.         
  382.         /* Compute error for NeXT Step */
  383.         err += dv2;
  384.         if (err >= du) {
  385.         ofs += vofs;
  386.         err -= du2;
  387.         }
  388.         ofs += uofs;
  389.     }
  390.     }
  391.     
  392. #if 0
  393.     if (mode == RALTER_PIXELS) {
  394.         RColorOffset *cdelta = (RColorOffset*)cdata;
  395.         register short r, g, b, a;
  396.  
  397.         for (i=0; i<=last; i++) {
  398.             /* Change the pixel with offset */
  399.             r = (short)*sr + cdelta->red;
  400.             g = (short)*sg + cdelta->green;
  401.             b = (short)*sb + cdelta->blue;
  402.             if (r>255) r = 255; else if (r<0) r = 0;
  403.             if (g>255) g = 255; else if (g<0) g = 0;
  404.             if (b>255) b = 255; else if (b<0) b = 0;
  405.             *sr = (unsigned char) r;
  406.             *sg = (unsigned char) g;
  407.             *sb = (unsigned char) b;
  408.             if (image->data[3]) {
  409.                 a = (short)*sa + cdelta->alpha;
  410.                 if (a>255) a = 255; else if (a<0) a = 0;
  411.                 *sa = (unsigned char) a;
  412.             }
  413.  
  414.             /* Compute error for NeXT Step */
  415.             err += dv2;
  416.             if (err >= du) {
  417.                 sr += vofs; sg += vofs;
  418.                 sb += vofs; sa += vofs;
  419.                 err -= du2;
  420.             }
  421.             sr += uofs; sg += uofs;
  422.             sb += uofs; sa += uofs;
  423.         }
  424.     } else {
  425.         RColor *color = (RColor*)cdata;
  426.  
  427.         if (color->alpha==255) {
  428.             for (i=0; i<=last; i++) {
  429.                 /* Draw the pixel */
  430.                 *sr = color->red;
  431.                 *sg = color->green;
  432.                 *sb = color->blue;
  433.                 if (image->data[3])
  434.                     *sa = 255;
  435.  
  436.                 /* Compute error for NeXT Step */
  437.                 err += dv2;
  438.                 if (err >= du) {
  439.                     sr += vofs; sg += vofs;
  440.                     sb += vofs; sa += vofs;
  441.                     err -= du2;
  442.                 }
  443.                 sr += uofs; sg += uofs;
  444.                 sb += uofs; sa += uofs;
  445.             }
  446.         } else {
  447.             register short alpha, nalpha, r, g ,b;
  448.  
  449.             alpha = color->alpha;
  450.             nalpha = 255 - alpha;
  451.             r = color->red;
  452.             g = color->green;
  453.             b = color->blue;
  454.  
  455.             for (i=0; i<=last; i++) {
  456.                 /* Draw the pixel */
  457.                 *sr = (((int)*sr * nalpha) + (r * alpha))/256;
  458.                 *sg = (((int)*sg * nalpha) + (g * alpha))/256;
  459.                 *sb = (((int)*sb * nalpha) + (b * alpha))/256;
  460.                 if (image->data[3])
  461.                     *sa = alpha + ((int)*sa * nalpha)/256;
  462.  
  463.                 /* Compute error for NeXT Step */
  464.                 err += dv2;
  465.                 if (err >= du) {
  466.                     sr += vofs; sg += vofs;
  467.                     sb += vofs; sa += vofs;
  468.                     err -= du2;
  469.                 }
  470.                 sr += uofs; sg += uofs;
  471.                 sb += uofs; sa += uofs;
  472.             }
  473.         }
  474.     }
  475. #endif
  476.     return True;
  477. }
  478.  
  479.  
  480. int
  481. RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color)
  482. {
  483.     return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False);
  484. }
  485.  
  486.  
  487. int
  488. ROperateLine(RImage *image, int operation, int x0, int y0, int x1, 
  489.          int y1, RColor *color)
  490. {
  491.     return genericLine(image, x0, y0, x1, y1, color, operation, False);
  492. }
  493.  
  494.  
  495. void
  496. RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
  497. {
  498.     register int x1, y1, x2, y2, i;
  499.  
  500.     assert(points!=NULL);
  501.  
  502.     if (npoints==0)
  503.         return;
  504.  
  505.     x1 = points[0].x;
  506.     y1 = points[0].y;
  507.     x2 = y2 = 0;
  508.  
  509.     for (i=1; i<npoints-1; i++) {
  510.         if (mode == RAbsoluteCoordinates) {
  511.             x2 = points[i].x;
  512.             y2 = points[i].y;
  513.         } else {
  514.             x2 += points[i-1].x;
  515.             y2 += points[i-1].y;
  516.         }
  517.         /* Don't draw pixels at junction points twice */
  518.         genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
  519.         x1 = x2;
  520.         y1 = y2;
  521.     }
  522.     i = npoints-1; /* last point */
  523.     if (mode == RAbsoluteCoordinates) {
  524.         x2 = points[i].x;
  525.         y2 = points[i].y;
  526.     } else {
  527.         x2 += points[i-1].x;
  528.         y2 += points[i-1].y;
  529.     }
  530.     i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
  531.     genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
  532. }
  533.  
  534.  
  535. void
  536. ROperateLines(RImage *image, int operation, RPoint *points,
  537.             int npoints, int mode, RColor *color)
  538. {
  539.     register int x1, y1, x2, y2, i;
  540.  
  541.     assert(points!=NULL);
  542.  
  543.     if (npoints==0)
  544.         return;
  545.  
  546.     x1 = points[0].x;
  547.     y1 = points[0].y;
  548.     x2 = y2 = 0;
  549.  
  550.     for (i=1; i<npoints-1; i++) {
  551.         if (mode == RAbsoluteCoordinates) {
  552.             x2 = points[i].x;
  553.             y2 = points[i].y;
  554.         } else {
  555.             x2 += points[i-1].x;
  556.             y2 += points[i-1].y;
  557.         }
  558.         /* Don't draw pixels at junction points twice */
  559.         genericLine(image, x1, y1, x2, y2, color, operation, True);
  560.         x1 = x2;
  561.         y1 = y2;
  562.     }
  563.     i = npoints-1; /* last point */
  564.     if (mode == RAbsoluteCoordinates) {
  565.         x2 = points[i].x;
  566.         y2 = points[i].y;
  567.     } else {
  568.         x2 += points[i-1].x;
  569.         y2 += points[i-1].y;
  570.     }
  571.     i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
  572.     genericLine(image, x1, y1, x2, y2, color, operation, i);
  573. }
  574.  
  575.  
  576. void
  577. RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
  578. {
  579.     register int i;
  580.  
  581.     assert(segs!=NULL);
  582.  
  583.     for (i=0; i<nsegs; i++) {
  584.         genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
  585.                     RNormalOperation, False);
  586.         segs++;
  587.     }
  588. }
  589.  
  590.  
  591. void
  592. ROperateSegments(RImage *image, int operation, RSegment *segs, 
  593.          int nsegs, RColor *color)
  594. {
  595.     register int i;
  596.  
  597.     assert(segs!=NULL);
  598.  
  599.     for (i=0; i<nsegs; i++) {
  600.         genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
  601.                     operation, False);
  602.         segs++;
  603.     }
  604. }
  605.  
  606.